/*
 * Copyright (c) 2007-2011, Petr Panteleyev
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *    3. The name of the author may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.panteleyev.gclient;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;

import javax.swing.AbstractAction;
import javax.swing.Box;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.border.BevelBorder;
import javax.swing.border.SoftBevelBorder;
import javax.swing.table.AbstractTableModel;

import org.panteleyev.blogclient.BloggerHistoryFrame;
import org.panteleyev.blogclient.BloggingKit;
import org.panteleyev.blogclient.DatePicker;
import org.panteleyev.blogclient.MainClass;
import org.panteleyev.blogclient.Options;
import org.panteleyev.blogclient.events.PostDeletedEvent;
import org.panteleyev.swing.ClipboardUtil;
import org.panteleyev.swing.OSUtil;
import org.panteleyev.swing.SwingFactory;
import org.panteleyev.swing.SwingWorkerEx;
import org.panteleyev.swing.TableUtil;
import org.panteleyev.swing.events.UpdateFrameEvent;

/**
 *
 * @author  Petr Panteleyev
 */
public class GBHistoryFrame extends BloggerHistoryFrame<GBUserProfile,GBEntry> {

    public static final int MAX_RES_DEFAULT = 20;

    /*
     * Actions
     */
    private AbstractAction      _viewCommentsAction;
    private AbstractAction      _copyEntryLinkAction;
    private AbstractAction      _openEntryLinkAction;

    private GBAccount           _account;
    private int                 _maxResults;

    private DatePicker         beforeDatePicker;
    private DatePicker         afterDatePicker;

    private final String[] historyTableHeaderNames = {
        " ",
        getTableDateColumnHeader(),
        getTableSubjectColumnHeader(),
        "C",
    };

    // Controls
    private JComboBox           blogsComboBox;
    private JComboBox<Integer>  lastComboBox;
    private JCheckBox           beforeCheck;
    private JCheckBox           afterCheck;

    private class HistoryUpdateThread extends SwingWorkerEx<Object,Object> {

        HistoryUpdateThread() {
            super(GBHistoryFrame.this, getBusyLabel());
            enableActions(false);
        }

        @Override
        protected Object doInBackground() throws Exception {
            try {
                int blogIndex = blogsComboBox.getSelectedIndex();
                GBlog blog = _account.getBlog(blogIndex);

                try {
                    // TODO: check here
                   _maxResults = (Integer)lastComboBox.getSelectedItem();
                } catch (NumberFormatException e) {
                    _maxResults = MAX_RES_DEFAULT;
                }

                Date beforeDate = null;
                if (beforeCheck.isSelected()) {
                    beforeDate = beforeDatePicker.getDate();
                }

                Date afterDate = null;
                if (afterCheck.isSelected()) {
                    afterDate = afterDatePicker.getDate();
                }

                setHistory(_account.getEntries(blog, _maxResults, afterDate, beforeDate, getProfile().getCommentCountAutoLoad()));
            } catch (Exception e) {
                setException(e);
            }

            return null;
        }

        @Override
        protected void done() {
            if (getException() == null) {
                getTableModel().fireTableDataChanged();
                TableUtil.adjustTableColumnSizes(getTable(), 2, getScroller());
            } else {
                handleException(getException());
            }
            enableActions(true);
            super.done();
        }
    }

    private class DeleteEventsThread extends SwingWorkerEx<Void,Integer> {
        private int[] rows;
        private ArrayList<GBEntry> toDelete;

        DeleteEventsThread(int[] rows) {
            super(GBHistoryFrame.this, getBusyLabel());
            this.rows = rows;
            toDelete = new ArrayList<>(rows.length);
            enableActions(false);
        }

        @Override
        protected Void doInBackground() throws Exception {
            /* Delete events from account */
            try {
                for (int index : rows) {
                    GBEntry entry = getHistory().get(index);
                    _account.deleteEntry(entry);
                    toDelete.add(entry);
                }
            } catch (Exception e) {
            }

            return null;
        }

        @Override
        protected void done() {
            for (GBEntry entry : toDelete) {
                getProfile().sendApplicationEvent(new PostDeletedEvent(this, entry));
                getHistory().remove(entry);
            }
            getTableModel().fireTableDataChanged();

            enableActions(true);
            super.done();
        }
    }

    public GBHistoryFrame(GBUserProfile profile) {
        super(profile);
        _maxResults = MAX_RES_DEFAULT;

        _account = profile.getAccount();
        initComponents();
        createMenuBar();
        createPopupMenu();

        createHistoryTable();

        receive(new UpdateFrameEvent(this));

        Options.getBounds(this);
    }

    private void initComponents() {
        DefaultComboBoxModel model = new DefaultComboBoxModel() {
            private ArrayList<GBlog> blogs = _account.getBlogs();

            @Override
            public int getSize() { return blogs.size(); }
            @Override
            public Object getElementAt(int index) {
                return blogs.get(index).getTitle();
            }
        };

        getContentPane().setLayout(new BorderLayout());

        getContentPane().add(
            SwingFactory.createPanel(new SoftBevelBorder(BevelBorder.RAISED),
                SwingFactory.LAYOUT.BOX_X,
                blogsComboBox = new JComboBox(model),
                Box.createHorizontalStrut(5),
                new JLabel(getLastLabel()),
                Box.createHorizontalStrut(3),
                lastComboBox = new JComboBox<>(new Integer[] {10, 20, 30, 40, 50}),
                Box.createHorizontalStrut(5),
                beforeCheck = new JCheckBox(),
                Box.createHorizontalStrut(3),
                beforeDatePicker = new DatePicker(),
                Box.createHorizontalStrut(5),
                afterCheck = new JCheckBox(),
                Box.createHorizontalStrut(3),
                afterDatePicker = new DatePicker(),
                Box.createHorizontalGlue(),
                getBusyLabel()
            ), BorderLayout.NORTH
        );

        SwingFactory.setWidthMaximumToPreferred(lastComboBox);

        beforeDatePicker.setEnabled(false);
        afterDatePicker.setEnabled(false);

        beforeCheck.setAction(new AbstractAction(getBeforeCheckBoxLabel()) {
            @Override
            public void actionPerformed(ActionEvent e) {
                beforeDatePicker.setEnabled(beforeCheck.isSelected());
            }
        });
        afterCheck.setAction(new AbstractAction(getAfterCheckBoxLabel()) {
            @Override
            public void actionPerformed(ActionEvent e) {
                afterDatePicker.setEnabled(afterCheck.isSelected());
            }
        });

        blogsComboBox.setSelectedIndex(0);
        lastComboBox.setSelectedIndex(1);

        getContentPane().add(getScroller(), BorderLayout.CENTER);
    }

    private GBAccount getAccount() {
        return _account;
    }

    @Override
    public void update() {
        new HistoryUpdateThread().execute();
    }

    @Override
    protected void createActions() {
        super.createActions();

        _viewCommentsAction = new ViewCommentsAction() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onViewComments();
            }
        };
        addAction(_viewCommentsAction);

        _copyEntryLinkAction = new BloggingKit.HistoryWindowCopyEntryLinkAction() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onCopyEntryLink();
            }
        };
        addAction(_copyEntryLinkAction);

        _openEntryLinkAction = new BloggingKit.HistoryWindowOpenEntryLinkAction() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onOpenEntryLink();
            }
        };
        addAction(_openEntryLinkAction);
    }

    private void createMenuBar() {
        createMenuBar(
            createFileMenu(),
            createMenu(getHistoryMenuName(), null,
                getEditEventAction(),
                getDeleteEventAction(),
                null,
                _viewCommentsAction,
                null,
                _copyEntryLinkAction,
                _openEntryLinkAction,
                null,
                getExportEventsAction()
            ),
            createProfileMenu(),
            createToolsMenu(),
            createWindowMenu(),
            createHelpMenu()
        );
    }

    private void createPopupMenu() {
        getScroller().setComponentPopupMenu(createMenu(null, null,
            getEditEventAction(),
            getDeleteEventAction(),
            null,
            _viewCommentsAction,
            null,
            _copyEntryLinkAction,
            _openEntryLinkAction,
            null,
            getExportEventsAction()
        ).getPopupMenu());
    }

    private String getLinkOfSelectedEntry() {
        int row = getTable().getSelectedRow();
        if (row != -1) {
            GBEntry event = getHistory().get(row);
            if ((event != null) && (!event.isDraft())) {
                URL url = event.getEntryURL();
                return (url == null)? null : url.toString();
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    private void onCopyEntryLink() {
        ClipboardUtil.put(getLinkOfSelectedEntry());
    }

    private void onOpenEntryLink() {
        String url = getLinkOfSelectedEntry();
        if (url != null) {
            OSUtil.runBrowser(url);
        }
    }

    private void onViewComments() {
        int row = getTable().getSelectedRow();
        if (row != -1) {
            GBEntry event = getHistory().get(row);
            if ((event != null) && (!event.isDraft())) {
                getProfile().openCommentsWindow(event);
            }
        }
    }

    @Override
    protected void editEvent() {
        int index = getTable().getSelectedRow();
        if (index != -1) {
            GBEntry entry = getHistory().get(index);
            new GBOpenPostThread(getProfile(), entry).execute();
        }
    }

    @Override
    protected void deleteEvent() {
        final int[] rows = getTable().getSelectedRows();
        if (rows.length == 0) {
            return;
        }

        if (!MainClass.showConfirmDialog(this)) {
            return;
        }

        new DeleteEventsThread(rows).execute();
    }

    private void createHistoryTable() {
        setTableModel(new AbstractTableModel() {
            @Override
            public int getColumnCount() {
                return historyTableHeaderNames.length;
            }

            @Override
            public int getRowCount() {
                return getHistory().size();
            }

            @Override
            public Object getValueAt(int row, int col) {
                return getHistory().get(row);
            }

            @Override
            public String getColumnName(int column) {
                return historyTableHeaderNames[column];
            }
        });

        getTable().setDefaultRenderer(Object.class, new GBHistoryTableCellRenderer(getProfile()));
    }

}
